use regex::Regex;
use std::os::windows::process::CommandExt;
use std::path::Path;
use std::{
    io::{BufRead, BufReader},
    process::{Command, Stdio},
};
use tauri::{AppHandle, Emitter};

#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[tauri::command]
async fn run_ffmpeg(
    app_handle: AppHandle,
    input_path: String,
    output_path: String,
    options: String,
) -> Result<(), String> {
    // 提取输入文件的文件名
    let input_path = Path::new(&input_path);
    let output_path = Path::new(&output_path);

    // 如果输出路径是目录，则将输入文件名添加到输出路径
    let file_name = input_path
        .file_name()
        .ok_or_else(|| "输入路径无效".to_string())?;
    let output_file_name = output_path.join(file_name);

    // 克隆输入路径、输出路径和选项，以确保它们在闭包的生命周期内有效
    let input_path_clone = input_path.to_path_buf();
    let output_file_name_clone = output_file_name.clone();
    let options_clone = options.clone();

    // 创建命令
    let mut ffmpeg_cmd = Command::new("ffmpeg/bin/ffmpeg.exe")
        .arg("-loglevel")
        .arg("debug") // 这里设置一个较低的日志级别，输出所有详细信息
        .arg("-y")
        .arg("-hide_banner")
        .arg("-i")
        .arg(&input_path_clone)
        .args(options_clone.split_whitespace())
        .arg(&output_file_name_clone)
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .creation_flags(0x08000000) // CREATE_NO_WINDOW flag
        .spawn()
        .map_err(|e| e.to_string())?; // 启动ffmpeg进程

    // 获取ffmpeg进程的stderr
    let stderr = ffmpeg_cmd.stderr.as_mut().unwrap();
    let reader = BufReader::new(stderr);

    // 用于匹配包含"frame="的行
    let frame_re = Regex::new(r"frame=\s*\d+").unwrap();

    // 读取stderr的每一行，分析进度信息
    for line in reader.lines() {
        let line = line.map_err(|e| e.to_string())?;
        if frame_re.is_match(&line) {
            println!("line====={}", line); // 只打印包含"frame="的行
            app_handle.emit("ffmpeg_log", line).map_err(|e| e.to_string())?;
        }
    }

    // 等待ffmpeg进程执行完毕
    let _ = ffmpeg_cmd.wait().map_err(|e| e.to_string())?;

    Ok(())
}

#[tauri::command]
async fn run_ffmpeg_batch(
    app_handle: AppHandle,
    input_path: String,
    output_path: String,
    options: String,
    supported_formats: String,
) -> Result<(), String> {
    let input_dir = Path::new(&input_path);
    let output_dir = Path::new(&output_path);

    if !input_dir.is_dir() {
        return Err("输入路径必须是目录".to_string());
    }

    if !output_dir.is_dir() {
        return Err("输出路径必须是目录".to_string());
    }

    // 将支持的格式字符串分割成Vec
    let formats: Vec<&str> = supported_formats.split_whitespace().collect();

    // 遍历输入目录中的所有文件
    for entry in std::fs::read_dir(input_dir).map_err(|e| e.to_string())? {
        let entry = entry.map_err(|e| e.to_string())?;
        let path = entry.path();

        // 跳过目录
        if path.is_dir() {
            continue;
        }

        // 检查文件扩展名是否在支持的格式列表中
        let extension = path.extension()
            .and_then(|ext| ext.to_str())
            .unwrap_or("");
        
        let is_supported = formats.iter().any(|format| {
            format.trim_start_matches("*.") == extension
        });

        if !is_supported {
            continue;
        }

        // 获取文件名
        let file_name = path.file_name().ok_or_else(|| "无效的文件名".to_string())?;
        let output_file = output_dir.join(file_name);

        // 克隆路径和选项
        let input_path_clone = path.clone();
        let output_file_clone = output_file.clone();
        let options_clone = options.clone();

        // 为每个文件创建ffmpeg命令
        let mut ffmpeg_cmd = Command::new("ffmpeg/bin/ffmpeg.exe")
            .arg("-loglevel")
            .arg("debug")
            .arg("-y")
            .arg("-hide_banner")
            .arg("-i")
            .arg(&input_path_clone)
            .args(options_clone.split_whitespace())
            .arg(&output_file_clone)
            .stdin(Stdio::null())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .creation_flags(0x08000000)
            .spawn()
            .map_err(|e| e.to_string())?;

        // 处理输出
        let stderr = ffmpeg_cmd.stderr.as_mut().unwrap();
        let reader = BufReader::new(stderr);
        let frame_re = Regex::new(r"frame=\s*\d+").unwrap();

        for line in reader.lines() {
            let line = line.map_err(|e| e.to_string())?;
            if frame_re.is_match(&line) {
                println!("line====={}", line);
                app_handle.emit("ffmpeg_log", line).map_err(|e| e.to_string())?;
            }
        }

        // 等待当前文件处理完成
        let _ = ffmpeg_cmd.wait().map_err(|e| e.to_string())?;
    }

    Ok(())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet, run_ffmpeg, run_ffmpeg_batch])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
